package com.lzy.netty.server;


import com.lzy.netty.utils.JedisPoolUtils;
import com.lzy.netty.utils.ZookeeperRegister;
import com.lzy.netty.websocket.WSServerinitializer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import redis.clients.jedis.Jedis;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author lzy
 * @date 2025/8/26 16:05
 * @description netty服务端
 **/
public class ChatServer2 {
    public static void main(String[] args) throws Exception{

        // 定义主从线程池
        // 定义主线程池，bossGroup只处理连接请求
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        // 定义从线程池，workerGroup处理业务逻辑
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        // Netty服务器启动的时候，从redis中查找有没有端口，如果没有则使用875，如果有则使用端口+10
        Integer nettyPort = selectPort(nettyDefaultPort);

        // 将服务器注册到zookeeper
        ZookeeperRegister.registerNettyServer("server-list",
                                                ZookeeperRegister.getLocalIp(),
                                                nettyPort);

        try {
            // 构建netty服务器
            ServerBootstrap serverBootstrap = new ServerBootstrap();         // 服务的启动类
            serverBootstrap.group(bossGroup, workerGroup)                    // 绑定主从线程池
                            .channel(NioServerSocketChannel.class)           // 设置NIO的双向通道
                            .childHandler(new WSServerinitializer());        // 设置处理器，用于处理workerGroup

            // 启动server，并且绑定端口875，同时启动方式为同步方式
            ChannelFuture channelFuture =  serverBootstrap.bind(nettyPort).sync();

            // 等待服务端监听端口关闭，同时启动方式为同步方式
            channelFuture.channel().closeFuture().sync();
        } finally {
            // 优雅关闭线程池
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }

    public static final Integer nettyDefaultPort = 875; // 885 895 905 915
    public static final String initOnlineCount = "0"; // 初始在线人数
    public static Integer selectPort(Integer port){
        String portKey = "netty_port";
        Jedis jedis = JedisPoolUtils.getJedis();

        Map<String,String> portMap = jedis.hgetAll(portKey);
        //  System.out.println(portMap);

        // 由于map中的key应该都是整数类型的port，所以先转换为整数后，再比对，使用string类型比对可能会出现问题
        List<Integer> portList = portMap.entrySet()
                .stream()
                .map(entry -> Integer.parseInt(entry.getKey()))
                .collect(Collectors.toList());

        //  System.out.println(portList);

        Integer nettyPort = null;
        if(portList == null || portList.isEmpty()){
            jedis.hset(portKey,port.toString(),initOnlineCount);
            nettyPort = port;
        }else{
            Integer maxPort = portMap.entrySet()
                    .stream()
                    .map(entry -> Integer.parseInt(entry.getKey()))
                    .reduce((p1, p2) -> p1 > p2 ? p1 : p2)
                    .get();
            // 基于最大端口号计算新端口（假设步长为10）
            Integer newPort = maxPort + 10;
            jedis.hset(portKey, newPort.toString(), initOnlineCount);
            nettyPort = newPort;
        }
        return nettyPort;
    }
}
